package escaleras.consola;

import Dominio.Entidades.Celda;
import Dominio.Entidades.Jugador;
import Dominio.Entidades.TipoPieza;
import Dominio.Fachada.Escalera;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.InputMismatchException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EscalerasConsola {

    private static Scanner consola = new Scanner(System.in);

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        Escalera sistemaEscalera = null;

        //Levanto el objeto serailizado
        File archivo = new File("elSistema");
        if (archivo.exists()) {
            ObjectInputStream oi = new ObjectInputStream(new BufferedInputStream(new FileInputStream("elSistema")));
            try {
                sistemaEscalera = (Escalera) oi.readObject();
                oi.close();
            } catch (Exception ex) {
                oi.close();
                if (archivo.delete()) {
                    System.out.println("El archivo seralizado no se puede reconstrir, se borrará.");
                } else {
                    System.out.println("El archivo seralizado no se puede borrar.");
                }
            }
        }
        //Si el objeto serializado no existe entonces creo una instancia nueva
        if (sistemaEscalera == null) {
            sistemaEscalera = new Escalera();
        }

        menuPrincipal(sistemaEscalera);

        archivo.delete();
        ObjectOutputStream oo = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("elSistema")));

        oo.writeObject(sistemaEscalera);

        oo.close();
    }

    private static int elegirOpcionMenuPrincipal() {
        int opcionElegida;

        System.out.println();
        System.out.println("Menú Principal");
        System.out.println("==============");
        System.out.println();
        String[] menuPrincipal = {"Ingresar un Jugador", "Iniciar Juego", "Rankin del Jugadores", "Ayuda del Juego", "Salir"};

        for (int i = 0; i < menuPrincipal.length; i++) {
            System.out.println((i + 1) + " - " + menuPrincipal[i]);
        }

        System.out.println();
        System.out.print("Ingrese la opción deseada: ");
        try {
            opcionElegida = consola.nextInt();
        } catch (InputMismatchException e) {
            System.out.println("Debe ingresar un número entero no mas de un digito de largo máximo.");
            //seteo en cero para que sea un valor incorrecto y entre en el default del switch
            opcionElegida = 0;
            consola.nextLine();
        }
        return opcionElegida;
    }

    private static void menuPrincipal(Escalera pSisEscalera) {
        try {
            boolean salir = false;

            do {
                int opcion = elegirOpcionMenuPrincipal();

                switch (opcion) {
                    /*Ingresar un Jugador*/
                    case 1: {

                        //ingreseJugador(pSisEscalera);
                        boolean ingreso = ingresoJugador(opcion, pSisEscalera);
                        if (ingreso) {
                            System.out.println("El jugador se creo satisfactoriamente . \n");
                        } else {
                            System.out.println();
                            System.out.println("No se pudo crear el Jugador. Contáctese con el administrador");
                        }
                        break;
                    }
                    /*Iniciar Juego*/
                    case 2: {

                        if (pSisEscalera.getListaDeJugadores().size() >= 2) {
                            menuIniciarPartida(pSisEscalera);
                        } else {
                            System.out.println("Para comenzar una partida debe de ingresar al menos 2 jugadores. \n");
                        }
                        break;
                    }
                    /*Rankin del Jugadores*/
                    case 3: {

                        rankingJugadores(pSisEscalera);
                        break;
                    }
                    //"Ayuda de Jugo"
                    case 4: {
                        System.out.println();
                        System.out.println(ayuda());
                        System.out.println("Para volver a menu presione ENTER");
                        System.out.println();
                        consola.nextLine();
                        break;
                    }
                    /*Salir*/
                    case 5: {

                        System.out.println("Fin del programa");
                        salir(pSisEscalera);
                        break;
                    }
                    default:
                        System.out.println();
                        System.out.println("Ingresó una opción incorrecta. La opciones estan disponibles en la ayuda ingresando ?");
                        System.out.println();
                        break;
                }
            } while (!salir);
        } catch (Exception e) {
            System.out.println(String.format("Se podujo el siguiente error: {0}", e.getMessage()));
        }
    }

    /*Opciones de lado de tablero
     * 1 - 4*4
     * 2 - 6*6
     * 3 - 8*8
     */
    private static int elegirOpcionTablero() {
        int opcionElegida;

        System.out.println();
        System.out.println("Seleccione el lado del tablero");
        System.out.println("==============================");
        System.out.println();
        String[] menuPrincipal = {"4*4", "6*6", "8*8"};

        for (int i = 0; i < menuPrincipal.length; i++) {
            System.out.println((i + 1) + " - " + menuPrincipal[i]);
        }

        System.out.println();
        System.out.print("Ingrese la opción deseada: ");
        try {
            opcionElegida = consola.nextInt();
        } catch (InputMismatchException e) {
            System.out.println("Debe ingresar un número entero no mas de un digito de largo máximo.");
            //seteo en cero para que sea un valor incorrecto y entre en el default del switch
            opcionElegida = 0;
            consola.nextLine();
        }
        return opcionElegida;
    }

    /*Solicita los datos basicos para comenzar una partida de Escaleras
     * Jugador Blanco
     * Jugador Negro
     * Lado del tablero
     * Cantidad máxima de jugadas en la partida.
     * Cantidad máxima de ladrillos L por jugador.
     */
    private static void menuIniciarPartida(Escalera pSisEscalera) {

        boolean ingreso = false;
        String blanco = null;
        String negro = null;
        int dimencion = 0;
        int cantidadJugadas = 0;
        int cantidadL = 0;
        try {

            //cuando se valida todo, se crea el objeto jugador
            consola.nextLine();
            while (!ingreso) {
                System.out.print("Ingrese  alias del Jugador Blanco: ");
                blanco = consola.nextLine();
                if (validarTexto(blanco)) {
                    if (pSisEscalera.existeJugador(blanco)) {
                        ingreso = true;
                    } else {
                        System.out.println("El  Jugador: " + blanco + " no  existe.");
                    }
                } else {
                    System.out.println("No se ha ingresado datos");
                }
            }

            ingreso = false;
            //cuando se valida todo, se crea el objeto jugador
            while (!ingreso) {
                System.out.print("Ingrese  alias del Jugador Negro: ");
                negro = consola.nextLine();
                if (validarTexto(negro)) {
                    if (pSisEscalera.existeJugador(negro)) {
                        if (negro.equals(blanco)) {
                            negro = null;
                            System.out.println("El  Jugador: " + negro + " tiene que ser diferente al selecionada anteriormente.");
                        } else {
                            ingreso = true;
                        }
                    } else {
                        System.out.println("El  Jugador: " + negro + " no  existe.");
                    }
                } else {
                    System.out.println("No se ha ingresado datos");
                }
            }


            ingreso = false;
            while (!ingreso) {
                int opcion = elegirOpcionTablero();

                switch (opcion) {
                    //"4*4"
                    case 1: {

                        ingreso = true;
                        dimencion = 4;
                        break;
                    }
                    //"6*6"
                    case 2: {

                        ingreso = true;
                        dimencion = 6;
                        break;
                    }
                    //"8*8"
                    case 3: {

                        ingreso = true;
                        dimencion = 8;
                        break;
                    }
                    default:
                        System.out.println("Opción  invalida");
                        System.out.println("");
                        break;
                }
            }

            ingreso = false;
            while (!ingreso) {
                System.out.print("Ingrese la cantidad limite de jugadas: ");
                cantidadJugadas = validarEntero();
                if (cantidadJugadas > 0) {
                    ingreso = true;
                } else {
                    System.out.println("Ingrese un valor mayor a 0.");
                }
            }

            ingreso = false;
            while (!ingreso) {
                System.out.print("Ingrese la cantidad limite de ladrillos L: ");
                cantidadL = validarEntero();
                if (cantidadL >= 0) {
                    cantidadL = (cantidadL == 0) ? Integer.MAX_VALUE : cantidadL;
                    ingreso = true;
                } else {
                    System.out.println("Re ingrese la cantidad.");
                }
            }
            pSisEscalera.crearPartida(blanco, negro, dimencion, cantidadL, cantidadJugadas);
            pSisEscalera.agregarPartida(pSisEscalera.getPartida());

            System.out.println("**************************************************************************");
            System.out.println(String.format("La partida comienza entre '%s' y '%s', la cantidad total de jugadas es %s.",
                    pSisEscalera.getPartida().getBlanco().getAlias(),
                    pSisEscalera.getPartida().getNegro().getAlias(),
                    pSisEscalera.getPartida().getCantidadMaximaJugadas()));
            System.out.println(String.format("Cada jugador dispone de %s ladrillos cuadrados, %s ladrillo rectangular y %s ladrillo/s L.",
                    pSisEscalera.getPartida().getCantidadC(),
                    pSisEscalera.getPartida().getCantidadR(),
                    pSisEscalera.getPartida().getCantidadL()));
            System.out.println("");

            consola.nextLine();
            menuJugada(pSisEscalera);
        } catch (Exception e) {
            System.out.println(String.format("Se podujo el siguiente error: {0}", e.getMessage()));
        }
        //return pPartida;
    }

    /*Menú Jugada
     * I - Ingresar su ficha
     * M - Mover su ficha
     * P - Poner un ladrillo
     * R - Retirar su ficha
     * X - Abandonar Partida 
     */
    private static String elegirOpcionJugada() throws Exception {
        String opcionElegida = "x";
        boolean invalido = true;

        System.out.println();
        System.out.println("Jugada");
        System.out.println("==============");
        System.out.println();
        String[] menuPrincipal = {"I [Coordenadas]  - Ingresar su ficha",
            "M [Coordenadas]  - Mover su ficha",
            "P [Coordenadas]  - Poner un ladrillo",
            "R                - Retirar su ficha",
            "X                - Abandonar partida"};

        for (int i = 0; i < menuPrincipal.length; i++) {
            System.out.println(menuPrincipal[i]);
        }
        System.out.println();

        System.out.print("Ingrese la opción deseada: ");
        opcionElegida = consola.nextLine();

        return opcionElegida;
    }

    /*Menú Jugada
     * I - Ingresar su ficha
     * M - Mover su ficha
     * P - Poner un ladrillo
     * R - Retirar su ficha
     * X - Abandonar Partida 
     */
    private static void menuJugada(Escalera pSisEscalera) {
        boolean salir = false;
        String opcion;
        String espacio;
        String movimiento;
        try {
            do {
                try {
                    System.out.println(pSisEscalera.getPartida().turnoJugadorToString());
                    movimiento = elegirOpcionJugada().toUpperCase();
                    System.out.println();
                    //if (!pSisEscalera.finalDeLaPartida()) {
                    //throw new Exception("La partida a finalizado, el ganador es: " + pSisEscalera.getPartida().getGanador().getAlias());

                    //movimiento = consola.nextLine();
                    if (validarTexto(movimiento)) {
                        opcion = movimiento.substring(0, 1);

                        //Si la opcion NO ES Abandonar y NO tiene un espacio y No son validos los movimientos
                        if (!opcion.equals("X") && !opcion.equals("R")) {
                            espacio = movimiento.substring(1, 2);
                            movimiento = movimiento.substring(2, movimiento.length()).trim().toUpperCase();
                            if (!espacio.equals(" ") || !movimientosValidos(movimiento)) {
                                System.out.println("Su jugada tiene movimientos invalidos. El formato es: Opcion [LetraNumero]");
                            }
                        }
                        try {
                            switch (opcion){
                                //"Ingresar su ficha"
                                case "I": {

                                    if (movimiento.length() < 1 && movimiento.length() > 2) {
                                        throw new Exception("Debe ingresar un par de corrdenadas");
                                    }
                                    ingresarFicha(pSisEscalera, movimiento);
                                    break;
                                }
                                //"Mover su ficha"
                                case "M": {

                                    if (movimiento.length() < 1) {
                                        throw new Exception("Debe ingresar un par de corrdenadas");
                                    }
                                    moverFicha(pSisEscalera, movimiento);
                                    break;
                                }
                                //"Poner un ladrillo"
                                case "P": {

                                    if (movimiento.length() < 1 && movimiento.length() > 6) {
                                        throw new Exception("Debe ingresar un par de corrdenadas");
                                    }
                                    ponerLadrillo(pSisEscalera, movimiento);
                                    break;
                                }
                                //"Retirar su ficha"
                                case "R": {

                                    retirarFicha(pSisEscalera);
                                    break;
                                }
                                //"Abandonar Partida"
                                case "X": {

                                    if (abandonar(pSisEscalera)) {
                                        System.out.println("Abandonó la partida, gana el jugador " + pSisEscalera.getPartida().getGanador() + ".");
                                        salir = true;
                                    }
                                    break;
                                }
                                //"Ayuda de Jugo"
                                case "?": {
                                    System.out.println();
                                    System.out.println("En este momento la ayuda para el juego no esta disponible.");
                                    consola.nextLine();
                                    System.out.println();

                                    break;
                                }
                                default:
                                    System.out.println();
                                    System.out.println("Ingresó una opción incorrecta. La opciones estan disponibles en la ayuda ingresando ?");
                                    System.out.println();
                                    break;
                            }
                        } catch (Exception e) {
                            System.out.println(e.getMessage());
                        }
                        //Muestro el estado de la partida solo si ingreso, movio, puso o remito una pieza.
                        if ("IMPR".contains(opcion)) {
                            //Dibujamos el tablero
                            DibujaTablero dibuja = new DibujaTablero(pSisEscalera.getPartida().getTablero());
                            System.out.println(dibuja.toString());

                            //Luego de cada jugada indico el estado de los jugadores respecto a sus piezas
                            System.out.println(pSisEscalera.getPartida().toString());
                        }
                    } else {
                        System.out.println();
                        System.out.println("Ingresó una opción incorrecta. La opciones estan disponibles en la ayuda ingresando ?");
                        System.out.println();
                        //seteo en cero para que sea un valor incorrecto y entre en el default del switch
                        opcion = "";
                        consola.nextLine();
                    }
                    //}
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
            } while (!pSisEscalera.finalDeLaPartida(false) && !salir);
            System.out.println(pSisEscalera.getPartida().resultadoDeLaPartida());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private static void ingresarFicha(Escalera pSisEscalera, String pMovimientos) {
        try {
            pSisEscalera.agregarJugada(pSisEscalera.crearJugadaI(pMovimientos));
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private static void moverFicha(Escalera pSisEscalera, String pMovimientos) {
        try {
            pSisEscalera.agregarJugada(pSisEscalera.crearJugadaM(pMovimientos));
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private static void ponerLadrillo(Escalera pSisEscalera, String pMovimientos) {
        try {
            pSisEscalera.agregarJugada(pSisEscalera.crearJugadaP(null, pMovimientos));
        } catch (Exception e) {

            System.out.println(e.getMessage());// luego q pasa por aca imprime el dos
        }
    }

    private static void retirarFicha(Escalera pSisEscalera) {
        try {
            pSisEscalera.agregarJugada(pSisEscalera.crearJugadaR(TipoPieza.Ficha));
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }


    /*Abandona la partida el jugador pasado por parametro 
     * el otro jugador de la partida es el ganador     
     */
    private static boolean abandonar(Escalera pSisEscalera) {
        String respuesta;
        boolean abandono = false;
        try {
            //cuando se valida todo, se crea el objeto jugador
            while (!abandono) {
                System.out.print("Está por abandonar la partida, ¿desea hacerlo? Sí[s]/No[n]: ");
                respuesta = consola.nextLine();
                if (validarTexto(respuesta)) {
                    if (respuesta.toUpperCase().equals("S")) {
                        System.out.println("El  Jugador: " + pSisEscalera.getPartida().turnoJugador().getAlias() + " a abandonado la partida.");
                        pSisEscalera.abandonarPartida();
                        System.out.println("El  Ganador es: " + pSisEscalera.getPartida().getGanador().getAlias());
                        abandono = true;
                    } else {
                        abandono = false;
                    }
                } else {
                    System.out.println("No se ha ingresado datos");
                }
            }
        } catch (Exception e) {
            System.out.println(String.format("Se podujo el siguiente error: {0}", e.getMessage()));
        }
        return abandono;
    }

    /*Verifica que los movimientos ingresados por el usuario 
     * De acuerdo con el formato LetraNumero,
     * Siendo las letras ABCDEFGH las validas,
     * Siendo los números 12345678 los validos.*/
    private static boolean movimientosValidos(String pMovimientos) {
        boolean valido;
        //Esta expresion regular controla el formato de las coordenadas 
        //ingresado por el usuario
        Pattern p = Pattern.compile("(?:[A-H][1-8]).*?");
        Matcher m = p.matcher(pMovimientos);
        valido = m.replaceAll("").equals("");
        return valido;
    }

    /*Validar ingreso de datos para ingresar un jugador al sistema
     * Alias
     * Nombre
     * Edad
     */
    private static boolean ingresoJugador(int opcion, Escalera pSisEscalera) {
        boolean retorno = false;
        try {
            //Declaro variables
            String nombre = "";
            String alias = "";
            int edad = 0;

            boolean validado = false;

            System.out.println("\n" + "Ingrese los datos del Jugador: ");
            System.out.println("==============================");
            consola.nextLine();

            //cuando se valida todo, se crea el objeto jugador
            while (!validado) {
                System.out.print("Ingrese la alias: ");
                alias = consola.nextLine().trim();
                if (validarTexto(alias) && !(pSisEscalera.existeJugador(alias))) {
                    validado = true;
                } else {

                    if (pSisEscalera.existeJugador(alias)) {
                        System.out.println("El alias para el Jugador: " + alias + " ya existe.");
                    } else {
                        System.out.println("No se ha ingresado datos");
                    }
                }
            }

            validado = false;
            while (!validado) {
                System.out.print("Ingrese el nombre: ");
                nombre = consola.nextLine().trim();
                while (validarTexto(nombre) && (!validado)) {
                    validado = true;
                }
                if (!validado) {
                    System.out.println("No se ha ingresado datos");
                }
            }

            validado = false;
            while (!validado) {
                System.out.print("Ingrese la edad: ");
                edad = validarEntero();
                if (edad > 0) {
                    validado = true;
                } else {

                    System.out.println("Por favor ingrese una edad real");
                }
            }

            if (validado) {
                pSisEscalera.agregarJugador(pSisEscalera.crearJugador(nombre, alias, edad));
                retorno = true;
            }

        } catch (Exception e) {
            System.out.println(String.format("Se podujo el siguiente error: {0}", e.getMessage()));
        }
        return retorno;
    }

    /*Lista los jugadores ordenados por Ranking de juegos ganados*/
    private static void rankingJugadores(Escalera pSisEscalera) {
        try {
            for (Jugador jugador : pSisEscalera.rankingJugadores()) {
                System.out.print(jugador.toString());
            }

        } catch (Exception e) {
            System.out.println(String.format("Se podujo el siguiente error: {0}", e.getMessage()));
        }
    }

    private static String ayuda() {
        StringBuilder retorno = new StringBuilder();
        retorno.append("<En este momento la ayuda para el juego no esta disponible. Presione ENTER");
        return retorno.toString();
    }

    /*Finaliza la ejecución del jugo*/
    private static void salir(Escalera pSisEscalera) {
        ObjectOutputStream oo = null;
        try {
            oo = new ObjectOutputStream(new FileOutputStream("elSistema"));

            oo.writeObject(pSisEscalera);

            System.exit(1);


        } catch (FileNotFoundException ex) {
            Logger.getLogger(EscalerasConsola.class
                    .getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(EscalerasConsola.class
                    .getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                oo.close();


            } catch (IOException ex) {
                Logger.getLogger(EscalerasConsola.class
                        .getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /*Método que valida si un string es vacio*/
    private static boolean validarTexto(String unTexto) {
        boolean textoOk = false;
        if (!unTexto.equals("")) {
            textoOk = true;
        }
        return textoOk;
    }

    /*Método que valida que el dato ingresado sea un número de tipo entero*/
    private static int validarEntero() {
        int numero;
        try {
            numero = consola.nextInt();
        } catch (InputMismatchException e) {
            System.out.println("Debe ingresar un número entero o supera largo máximo.");
            numero = -1;
            consola.nextLine();
        }
        return numero;


    }

    private static class DibujaTablero {

        //Atributos
        private Celda[][] matriz;
        private String saltoLinea = "\n";
        private String margen = "   ";
        private String bordeTOP = "o---";
        private String bordeTOPFIN = "o---o";
        private String bordeTOPUsado = "****";
        private String bordeTOPUsadoFIN = "*****";
        private String bordeTOPAnterior = "*---";
        private String bordeTOPAnteriorFIN = "*---o";
        private String bordeTOPLindero = "*   ";
        private String bordeTOPLinderoFIN = "*   *";
        private String bordeLEF = "|   ";
        private String bordeLEFFIN = "|   |";
        private String bordeLEFAnterior = "*   ";
        private String bordeLEFAnteriorFIN = "*   |";
        private String bordeLEFUsado = "*%s%s%s";
        private String bordeLEFUsadoFIN = "*%s%s%s*";
        private String bordeLEFLindero = " %s%s%s";
        private String bordeLEFLinderoFIN = " %s%s%s*";
        private String bordeLEFFicha = "|%s%s%s";
        private String bordeLEFFichaFIN = "|%s%s%s|";
        private String bordeLEFFichaAnterior = "*%s%s%s";
        private String bordeLEFFichaAnteriorFIN = "*%s%s%s|";

        //Contructor con parametros
        public DibujaTablero(Celda[][] pMatriz) {
            this.matriz = pMatriz;
        }

//        public void setMatriz(Celda[][] matriz) {
//            this.matriz = matriz;
//        }
        @Override
        public String toString() {
            String tablero = null;
            try {
                tablero = dibujarTableroConCeldas();
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
            }
            return tablero;
        }

        private String dibujarTableroConCeldas() throws Exception {
            StringBuilder retorno = new StringBuilder();
            try {

                //System.out.println(cabezal);
                retorno.append(escribirNumeroColumna());
                //System.out.print(retorno);
                retorno.append(saltoLinea);
                //System.out.print(retorno);

                //Recorro la matriz por fila
                for (int posFila = 0; posFila < matriz.length; posFila++) {
                    Celda[] fila = matriz[posFila];

                    //Repito cada posicion cuatro veces para generar los renglones de una fila
                    for (int renglon = 0; renglon < 4; renglon++) {
                        //Escribo la letra de la fila cuando el renglon es el tecero
                        //y la columna es 0.
                        if (renglon == 2) {
                            retorno.append(escribirLetraFila(posFila));
                        } else {
                            retorno.append(margen);
                            //System.out.print(retorno);
                        }
                        //Recorro cada celda para ver si tengo que dibujarla con contenido
                        for (int posColumna = 0; posColumna < fila.length; posColumna++) {
                            Celda celda = fila[posColumna];
                            //linea = dibujarCeldaVacia(celda, r, linea, bordeTOPLimpio, bordeLeftLimpio);

                            if (renglon == 0) {
                                retorno.append(dibujarBrodeFila(posFila, celda, posColumna, fila));
                                //System.out.print(retorno);
                            } else {
                                retorno.append(dibujarRellenoFila(posColumna, celda, renglon, fila));
                                //System.out.print(retorno);
                            }

                        }
                        //System.out.println();
                        retorno.append(saltoLinea);
                        //System.out.print(retorno);
                    }
                    if (posFila == (matriz.length - 1)) {
                        retorno.append(dibujarBordeInferiorTablero(fila));
                        //System.out.print(retorno);
                    }
                }

            } catch (Exception e) {
                throw e;
            }
            return retorno.toString();
        }

        private String escribirNumeroColumna() {
            String retorno = "     ";
            for (int i = 0; i < matriz.length; i++) {
                retorno += (i + 1 + "   ");
            }
            return retorno;
        }

        private String escribirLetraFila(int pPosFila) {
            String retorno = "";
            switch (pPosFila) {
                case 0:
                    retorno = " A ";
                    break;
                case 1:
                    retorno = " B ";
                    break;
                case 2:
                    retorno = " C ";
                    break;
                case 3:
                    retorno = " D ";
                    break;
                case 4:
                    retorno = " E ";
                    break;
                case 5:
                    retorno = " F ";
                    break;
                case 6:
                    retorno = " G ";
                    break;
                case 7:
                    retorno = " H ";
                    break;
                default:
                    break;
            }
            return retorno;
        }

        private String dibujarBrodeFila(int pPosFila, Celda pCelda, int pPosColumna, Celda[] pFila) throws Exception {
            String retorno = "";
            try {
                //Si la fila es la primera 
                if (pPosFila == 0) {
                    //Si la celda no tiene datos
                    if (pCelda == null) {
                        //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                        retorno = (dibujarBordeTop(pPosColumna, pFila));
                        //System.out.print(retorno);

                        //Si la columna no es la primera
                        if (pPosColumna > 0) {

                            //Si la celda izquierda tiene datos
                            if (pFila[pPosColumna - 1] != null) {

                                //Si la celda izquierda es un ladrillo
                                if (pFila[pPosColumna - 1].isEsLabrillo()) {

                                    //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                                    retorno = (dibujarBordeTopAnterior(pPosColumna, pFila));
                                    //System.out.print(retorno);
                                }
                            }
                        }
                    } else {
                        //Si la celda es un ladrillo
                        if (pCelda.isEsLabrillo()) {
                            //Dibujo el borde usado con fin o no, dependiendo si es el borde final o no.
                            retorno = (dibujarBordeTopUsado(pPosColumna, pFila));
                            //System.out.print(retorno);

                        } else {
                            //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                            retorno = (dibujarBordeTop(pPosColumna, pFila));
                            //System.out.print(retorno);

                            //Si la columna no es la primera
                            if (pPosColumna > 0) {

                                //Si la celda izquierda tiene datos
                                if (pFila[pPosColumna - 1] != null) {

                                    //Si la celda izquierda es un ladrillo
                                    if (pFila[pPosColumna - 1].isEsLabrillo()) {

                                        //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                                        retorno = (dibujarBordeTopAnterior(pPosColumna, pFila));
                                        //System.out.print(retorno);
                                    }
                                }
                            }
                        }
                    }
                } else {
                    //Si la fila no es la primera
                    //Si la celda no tiene datos
                    if (pCelda == null) {

                        //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                        retorno = (dibujarBordeTop(pPosColumna, pFila));
                        //System.out.print(retorno);

                        //Si la celda de arriba no tiene datos
                        if (this.matriz[pPosFila - 1][pPosColumna] == null) {
                            //Si no es la primera columna 
                            if (pPosColumna > 0) {
                                //Si la celda izquierda no tiene datos
                                if (pFila[pPosColumna - 1] == null) {
                                    //Si la celda de arriba en diagonal izquierda tiene datos
                                    if (this.matriz[pPosFila - 1][pPosColumna - 1] != null) {
                                        //Si la celda de arriba en diagonal izquierda es un ladrillo
                                        if (this.matriz[pPosFila - 1][pPosColumna - 1].isEsLabrillo()) {
                                            //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                                            retorno = (dibujarBordeTopAnterior(pPosColumna, pFila));
                                            //System.out.print(retorno);
                                        }
                                    }
                                } else {
                                    //Si la celda izquierda es un ladrillo
                                    if (pFila[pPosColumna - 1].isEsLabrillo()) {

                                        //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                                        retorno = (dibujarBordeTopAnterior(pPosColumna, pFila));
                                        //System.out.print(retorno);
                                        //System.out.print(retorno + "" + pPosFila + "" + pPosColumna+ "|" );
                                    }
                                }
                            }
                        } else {
                            //Si la celda es null
                            //Si la celda de arriba tiene datos

                            //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                            retorno = (dibujarBordeTopAnterior(pPosColumna, pFila));
                            //System.out.print(retorno);

                            //Si la celda de arriba es un ladirllo
                            if (this.matriz[pPosFila - 1][pPosColumna].isEsLabrillo()) {
                                //Dibujo el borde usado con fin o no, dependiendo si es el borde final o no.
                                retorno = (dibujarBordeTopUsado(pPosColumna, pFila));
                                //System.out.print(retorno);
                            } else {
                                //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                                retorno = (dibujarBordeTop(pPosColumna, pFila));
                                //System.out.print(retorno); 
                                //Si no es la primera columna 
                                if (pPosColumna > 0) {
                                    //Si la celda izquierda tiene datos
                                    if (pFila[pPosColumna - 1] != null) {
                                        //Si la celda izquierda es un ladrillo
                                        if (pFila[pPosColumna - 1].isEsLabrillo()) {
                                            //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                                            retorno = (dibujarBordeTopAnterior(pPosColumna, pFila));
                                            //System.out.print(retorno);
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        //Si la celda es un ladrillo
                        if (pCelda.isEsLabrillo()) {

                            //Dibujo el borde usado con fin o no, dependiendo si es el borde final o no.
                            retorno = (dibujarBordeTopUsado(pPosColumna, pFila));
                            //System.out.print(retorno);

                            //Si la celda de arriba tiene datos
                            if (this.matriz[pPosFila - 1][pPosColumna] != null) {

                                //Si la celda y la anterior estan en el mismo nivel
                                if (pCelda.getNivel() == this.matriz[pPosFila - 1][pPosColumna].getNivel()) {

                                    //Si la celda es parte de un ladrillo
                                    if (pCelda.isLinderoTOP()) {
                                        //Dibujo el borde usado con fin o no, dependiendo si es el borde final o no.
                                        retorno = (dibujarBordeTopLindero(pPosColumna, pFila));
                                        //System.out.print(retorno);
                                    }
                                }
                            }
                        } else {
                            //Si la celda no es un ladrillo

                            //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                            retorno = (dibujarBordeTop(pPosColumna, pFila));
                            //System.out.print(retorno);

                            //Si la celda de arriba tiene datos
                            if (this.matriz[pPosFila - 1][pPosColumna] != null) {
                                //Entonces dibujo un borde ****

                                if (this.matriz[pPosFila - 1][pPosColumna].isEsLabrillo()) {

                                    //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                                    retorno = (dibujarBordeTopUsado(pPosColumna, pFila));
                                    //System.out.print(retorno);
                                } else {

                                    //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                                    retorno = (dibujarBordeTop(pPosColumna, pFila));
                                    //System.out.print(retorno);
                                }
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                throw ex;
            }
            return retorno;
        }

        private String dibujarBordeTop(int pPosColumna, Celda[] pFila) {
            String retorno = "";

            if (pPosColumna == (pFila.length - 1)) {
                //System.out.print(bordeTOPFIN);
                retorno = bordeTOPFIN;
            } else {
                //System.out.print(bordeTOP);
                retorno = bordeTOP;
            }
            return retorno;
        }

        private String dibujarBordeTopUsado(int pPosColumna, Celda[] pFila) {
            String retorno = "";

            if (pPosColumna == (pFila.length - 1)) {
                //System.out.print(bordeTOPUsadoFIN);
                retorno = bordeTOPUsadoFIN;
            } else {
                //System.out.print(bordeTOPUsado);
                retorno = bordeTOPUsado;
            }
            return retorno;
        }

        private String dibujarBordeTopAnterior(int pPosColumna, Celda[] pFila) {
            String retorno = "";

            if (pPosColumna == (pFila.length - 1)) {
                //System.out.print(bordeTOPAnteriorFIN);
                retorno = bordeTOPAnteriorFIN;
            } else {
                //System.out.print(bordeTOPAnterior);
                retorno = bordeTOPAnterior;
            }
            return retorno;
        }

        private String dibujarBordeTopLindero(int pPosColumna, Celda[] pFila) {
            String retorno = "";

            if (pPosColumna == (pFila.length - 1)) {
                //System.out.print(bordeTOPLinderoFIN);
                retorno = bordeTOPLinderoFIN;
            } else {
                //System.out.print(bordeTOPLindero);
                retorno = bordeTOPLindero;
            }
            return retorno;
        }

        private String dibujarRellenoFila(int pPosColumna, Celda pCelda, int pRenglon, Celda[] pFila) throws Exception {
            String retorno = "";
            try {
                //Si la columna es la primera
                if (pPosColumna == 0) {

                    //Si la celda no tiene datos
                    if (pCelda == null) {

                        //Dibujo el relleno vacio con fin o no, dependiendo si es el borde final o no.
                        retorno = (dibujarBordeLeft(pPosColumna, pFila));
                        //System.out.print(retorno);
                    } else {

                        //Si la celda es un ladrillo
                        if (pCelda.isEsLabrillo()) {

                            //Dibujo el relleno de ladrillo con fin o no, dependiendo si es el borde final o no.
                            retorno = (dibujarRellenoLadrillo(pRenglon, pPosColumna, pCelda, pFila));
                            //System.out.print(retorno);
                        } else {

                            //Dibujo el relleno de ficha con fin o no, dependiendo si es el borde final o no.
                            retorno = (dibujarRellenoFicha(pRenglon, pPosColumna, pFila.length, null, pCelda));
                            //System.out.print(retorno);
                        }
                    }
                } else {
                    //Si no es la primer celda
                    //Si la celda no tiene datos
                    if (pCelda == null) {
                        //Dibujo el relleno vacio con fin o no, dependiendo si es el borde final o no.
                        retorno = (dibujarBordeLeft(pPosColumna, pFila));
                        //System.out.print(retorno);
                        //Si la celda izquierda tiene datos
                        if (pFila[pPosColumna - 1] != null) {
                            if (pFila[pPosColumna - 1].isEsLabrillo()) {
                                //Dibujo el relleno vacio con fin o no, dependiendo si es el borde final o no.
                                retorno = (dibujarRellenoLadrillo(pRenglon, pPosColumna, pCelda, pFila));
                                //System.out.print(retorno);
                            }
                        }
                    } else {
                        //Si la celda tiene datos.
                        //Si la celda actual es un ladrillo
                        if (pCelda.isEsLabrillo()) {

                            retorno = (dibujarRellenoLadrillo(pRenglon, pPosColumna, pCelda, pFila));
                            //Si la celda izquierda tiene datos.
                            if (pFila[pPosColumna - 1] != null) {

                                //Si la celda actual y la anterior pertenecen al mismo nivel
                                if (pCelda.getNivel() == pFila[pPosColumna - 1].getNivel()) {
                                    if (pCelda.isLinderoLEFT()) {
                                        retorno = (dibujarRellenoLindero(pRenglon, pPosColumna, pFila.length, pCelda));
                                    }
                                }
                            }
                        } else {
                            retorno = (dibujarRellenoFicha(pRenglon, pPosColumna, pFila.length, pFila[pPosColumna - 1], pCelda));
                        }
                    }
                }
            } catch (Exception ex) {
                throw ex;
            }
            return retorno;
        }

        private String dibujarRellenoLadrillo(int pRenglon, int pPosColumna, Celda pCelda, Celda[] pFila) throws Exception {
            String retorno = String.format(bordeLEFUsado, " ", " ", " ");
            try {
                //Si la celda tiene datos
                if (pCelda != null) {
                    //Si estamos en el renglo dos o tres
                    if (pRenglon == 1 || pRenglon == 3) {

                        if (pPosColumna == (pFila.length - 1)) {
                            //System.out.print(String.format(bordeLEFUsadoFIN, " ", pCelda.getNivel(), " "));
                            retorno = String.format(bordeLEFUsadoFIN, " ", pCelda.getNivel(), " ");
                        } else {
                            //System.out.print(String.format(bordeLEFUsado, " ", pCelda.getNivel(), " "));
                            retorno = String.format(bordeLEFUsado, " ", pCelda.getNivel(), " ");
                        }
                    }
                    if (pRenglon == 2) {
                        if (pPosColumna == (pFila.length - 1)) {
                            if (pCelda.getFicha() == null) {
                                retorno = String.format(bordeLEFUsadoFIN, pCelda.getNivel(), pCelda.getNivel(), pCelda.getNivel());
                            } else {
                                retorno = String.format(bordeLEFUsadoFIN, pCelda.getNivel(), pCelda.getFicha(), pCelda.getNivel());
                            }
                        } else {
                            if (pCelda.getFicha() == null) {
                                retorno = String.format(bordeLEFUsado, pCelda.getNivel(), pCelda.getNivel(), pCelda.getNivel());
                            } else {
                                retorno = String.format(bordeLEFUsado, pCelda.getNivel(), pCelda.getFicha(), pCelda.getNivel());
                            }
                        }
                    }
                } else {
                    if (pPosColumna > 0 && pFila[pPosColumna - 1] != null) {
                        retorno = dibujarBordeLeftAnterior(pPosColumna, pFila);
                    }
//                else {
//                    if (pPosColumna == (pFila.length - 1)) {
//                        retorno = String.format(bordeLEFUsadoFIN, " ", " ", " ");
//                    }
//                }
                }

            } catch (Exception ex) {
                throw ex;
            }
            return retorno;
        }

        private String dibujarRellenoFicha(int pRenglon, int pPosColumna, int pFilaLength, Celda pCeldaAnterior, Celda pCelda) throws Exception {
            String retorno = "";
            try {
                if (pRenglon == 1 || pRenglon == 3) {

                    if (pPosColumna == (pFilaLength - 1)) {
                        retorno = (String.format(bordeLEFFichaFIN, " ", (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", " "));
                        if (pCeldaAnterior != null) {
                            if (pCeldaAnterior.isEsLabrillo()) {
                                retorno = (String.format(bordeLEFFichaAnteriorFIN, " ", (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", " "));
                            }
                        }
                    } else {
                        if (pCeldaAnterior == null) {
                            retorno = (String.format(bordeLEFFicha, " ", (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", " "));
                        } else {
                            if (pCeldaAnterior.isEsLabrillo()) {
                                retorno = (String.format(bordeLEFFichaAnterior, " ", (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", " "));
                            } else {
                                retorno = (String.format(bordeLEFFicha, " ", (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", " "));
                            }
                        }
                    }
                }
                if (pRenglon == 2) {
                    if (pPosColumna == (pFilaLength - 1)) {

                        if (pCeldaAnterior == null) {
                            retorno = (String.format(bordeLEFFichaFIN, (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", pCelda.getFicha(), (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " "));
                        } else {
                            if (pCeldaAnterior.isEsLabrillo()) {
                                retorno = (String.format(bordeLEFFichaAnteriorFIN, (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", pCelda.getFicha(), (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " "));
                            } else {
                                retorno = (String.format(bordeLEFFichaFIN, (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", pCelda.getFicha(), (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " "));
                            }
                        }
                    } else {
                        if (pCeldaAnterior == null) {
                            retorno = (String.format(bordeLEFFicha, (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", pCelda.getFicha(), (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " "));
                        } else {
                            if (pCeldaAnterior.isEsLabrillo()) {
                                retorno = (String.format(bordeLEFFichaAnterior, (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", pCelda.getFicha(), (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " "));
                            } else {
                                retorno = (String.format(bordeLEFFicha, (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " ", pCelda.getFicha(), (pCelda.isEsLabrillo()) ? pCelda.getNivel() : " "));
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                throw ex;
            }
            return retorno;
        }

        private String dibujarRellenoLindero(int pRenglon, int pPosColumna, int pFilaLength, Celda pCelda) throws Exception {
            String retorno = "";
            try {
                if (pRenglon == 1 || pRenglon == 3) {

                    if (pPosColumna == (pFilaLength - 1)) {
                        //System.out.print(String.format(bordeLEFLinderoFIN, " ", pCelda.getNivel(), " "));
                        retorno = String.format(bordeLEFLinderoFIN, " ", pCelda.getNivel(), " ");
                    } else {
                        //System.out.print(String.format(bordeLEFLindero, " ", pCelda.getNivel(), " "));
                        retorno = String.format(bordeLEFLindero, " ", pCelda.getNivel(), " ");
                    }
                }
                if (pRenglon == 2) {
                    if (pPosColumna == (pFilaLength - 1)) {
                        if (pCelda.getFicha() == null) {
                            retorno = String.format(bordeLEFLinderoFIN, pCelda.getNivel(), pCelda.getNivel(), pCelda.getNivel());
                        } else {
                            retorno = String.format(bordeLEFLinderoFIN, pCelda.getNivel(), pCelda.getFicha(), pCelda.getNivel());
                        }
                    } else {
                        if (pCelda.getFicha() == null) {
                            retorno = String.format(bordeLEFLindero, pCelda.getNivel(), pCelda.getNivel(), pCelda.getNivel());
                        } else {
                            retorno = String.format(bordeLEFLindero, pCelda.getNivel(), pCelda.getFicha(), pCelda.getNivel());
                        }
                    }
                }

            } catch (Exception ex) {
                throw ex;
            }
            return retorno;
        }

        private String dibujarBordeLeft(int pPosColumna, Celda[] pFila) {
            String retorno = "";

            //Este bloque controla el caso de bore 
            //cuando la columna es la ultima
            if (pPosColumna == (pFila.length - 1)) {
                //System.out.print(bordeLEFFIN);
                retorno = bordeLEFFIN;
            } else {
                //System.out.print(bordeLEF);
                retorno = bordeLEF;
            }
            return retorno;
        }

        private String dibujarBordeLeftAnterior(int pPosColumna, Celda[] pFila) {
            String retorno = "";

            //Este bloque controla el caso de bore 
            //cuando la columna es la ultima
            if (pPosColumna == (pFila.length - 1)) {
                //System.out.print(bordeLEFFIN);
                retorno = bordeLEFAnteriorFIN;
            } else {
                //System.out.print(bordeLEF);
                retorno = bordeLEFAnterior;
            }
            return retorno;
        }

        private String dibujarBordeInferiorTablero(Celda[] pFila) throws Exception {
            StringBuilder retorno = new StringBuilder(margen);
            try {
                //System.out.print(margen);
                //Recorro cada celda para ver si tengo que dibujarla con contenido
                for (int posColumna = 0; posColumna < pFila.length; posColumna++) {
                    Celda celda = pFila[posColumna];
                    //Si la celda no tiene datos
                    if (celda == null) {
                        //Si no es la primera celda
                        if (posColumna > 0) {
                            //Si la celda izquierda no tiene datos
                            if (pFila[posColumna - 1] == null) {
                                //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                                retorno.append(dibujarBordeTop(posColumna, pFila));
                            } else {
                                //Si la celda izquierda es un ladrillo
                                if (pFila[posColumna - 1].isEsLabrillo()) {
                                    //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                                    retorno.append(dibujarBordeTopAnterior(posColumna, pFila));
                                    //System.out.print(retorno);
                                } else {
                                    //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                                    retorno.append(dibujarBordeTop(posColumna, pFila));
                                    //System.out.print(retorno);
                                }
                            }
                        } else {
                            //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                            retorno.append(dibujarBordeTop(posColumna, pFila));
                            //System.out.print(bordeTOP);
                        }
                    } else {
                        if (celda.isEsLabrillo()) {
                            //Dibujo el borde usado anterior con fin o no, dependiendo si es el borde final o no.
                            retorno.append(dibujarBordeTopUsado(posColumna, pFila));
                            //System.out.print(retorno);
                        } else {
                            //Dibujo el borde vacio con fin o no, dependiendo si es el borde final o no.
                            retorno.append(dibujarBordeTop(posColumna, pFila));
                            //System.out.print(retorno);
                        }
                    }
                }
                retorno.append(saltoLinea);

            } catch (Exception ex) {
                throw ex;
            }
            return retorno.toString();
        }
    }
}
